﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace UlsStudio.Engine
{
    /// <summary>
    /// Base settings implementation
    /// </summary>
    public abstract class ScanSettings
    {
        public ScanSettings() { this.ID = Guid.NewGuid(); }

        public Guid ID { get; set; }

        public abstract bool SettingsAreValid { get; }
    }

    /// <summary>
    /// Settings used to define a real-time-scanner job
    /// </summary>
    public class RealTimeScanSettings : ScanSettings
    {
        public RealTimeScanSettings()
        {
            this.Directories = new List<DirectoryInfo>();
        }
        public List<DirectoryInfo> Directories { get; set; }

        public override bool SettingsAreValid
        {
            get { return this.Directories.Count > 0; }
        }
    }

    /// <summary>
    /// Scan engine settings for loading ULS logs
    /// </summary>
    public class UlsScanSettings : ScanSettings
    {
        #region Constructors & Privates

        private string _ulsFolderLocation = string.Empty;
        private readonly List<FileInfo> _filesToBeScanned = null;

        public UlsScanSettings()
        {
            _filesToBeScanned = new List<FileInfo>();

        }

        public UlsScanSettings(List<FileInfo> filesToBeScanned)
            : this()
        {
            if (filesToBeScanned == null)
            {
                throw new ArgumentNullException("filesToBeScanned");
            }
            this._filesToBeScanned = filesToBeScanned;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Files to be scanned
        /// </summary>
        public List<FileInfo> FilesToBeScanned
        {
            get { return _filesToBeScanned; }
        }


        #endregion

        /// <summary>
        /// Get settings for a directory
        /// </summary>
        public static UlsScanSettings BuildSettingsFromDirectory(DirectoryInfo rootDir, bool includeSubFolders)
        {
            return BuildSettingsFromDirectory(rootDir, includeSubFolders, new FileFoundDelegate(FileFoundDefaultDelegate));
        }

        private static void FileFoundDefaultDelegate(FileInfo f)
        {
            Logging.Writeline("FileFound() - Adding {0} to file-targets", f.FullName);
        }

        /// <summary>
        /// Get settings for a directory
        /// </summary>
        public static UlsScanSettings BuildSettingsFromDirectory(DirectoryInfo rootDir, bool includeSubFolders, FileFoundDelegate fileFoundDelegate)
        {
            List<DirectoryInfo> dirs = new List<DirectoryInfo>(1);
            dirs.Add(rootDir);
            return BuildSettingsFromDirectories(dirs, includeSubFolders, fileFoundDelegate);
        }

        public static UlsScanSettings BuildSettingsFromDirectories(List<DirectoryInfo> dirs, bool includeSubFolders)
        {
            return BuildSettingsFromDirectories(dirs, includeSubFolders, new FileFoundDelegate(FileFoundDefaultDelegate));
        }
        public static UlsScanSettings BuildSettingsFromDirectories(List<DirectoryInfo> dirs, bool includeSubFolders, FileFoundDelegate fileFoundDelegate)
        {
            List<FileInfo> files = new List<FileInfo>();
            foreach (DirectoryInfo rootDir in dirs)
            {
                files.AddRange(GetLogFilesInDirectory(rootDir, includeSubFolders, fileFoundDelegate));
            }
            
            UlsScanSettings s = new UlsScanSettings(files);
            return s;
        }

        public delegate void FileFoundDelegate(FileInfo fileFound);

        /// <summary>
        /// Returns a list of files for scanning in a directory.
        /// </summary>
        /// <param name="dir"></param>
        /// <param name="includeSubFolders"></param>
        /// <param name="fileFoundDelegate"></param>
        /// <returns></returns>
        private static List<FileInfo> GetLogFilesInDirectory(DirectoryInfo dir, bool includeSubFolders, FileFoundDelegate fileFoundDelegate)
        {
            List<FileInfo> filesToScan = new List<FileInfo>();

            // Get each file
            try
            {
                var textFileNames = Directory.GetFiles(dir.FullName, "*.*", SearchOption.AllDirectories)
                    .Where(s => s.EndsWith(".log", StringComparison.OrdinalIgnoreCase) || s.EndsWith(".txt", StringComparison.OrdinalIgnoreCase));

                foreach (string logFileName in textFileNames)
                {
                    FileInfo thisFile = new FileInfo(logFileName);
                    fileFoundDelegate(thisFile);
                    filesToScan.Add(thisFile);
                }
                if (includeSubFolders)
                {
                    foreach (DirectoryInfo subDir in dir.GetDirectories())
                    {
                        filesToScan.AddRange(GetLogFilesInDirectory(subDir, includeSubFolders, fileFoundDelegate));
                    }
                }

            }
            catch (UnauthorizedAccessException)
            {
                Logging.Writeline("Access denied to '{0}'", dir.FullName);
            }
            

            return filesToScan;
        }

        /// <summary>
        /// Errors this settings-object has with 1 or more variable.
        /// </summary>
        public List<string> SettingsErrors
        {
            get
            {
                List<string> errs = new List<string>();
                foreach (FileInfo fileToLoad in this.FilesToBeScanned)
                {
                    if (!fileToLoad.Exists)
                    {
                        errs.Add(string.Format("File in batch '{0}' doesn't exist", fileToLoad.FullName));
                    }
                }

                return errs;
            }
        }

        public override bool SettingsAreValid
        {
            get { return this.FilesToBeScanned.Count > 0; }
        }
    }
}
